package client;

/* rzeczy do shaksowania

	- komendy do serwera

*/


import gui.ClientChatWindow;
import gui.ClientMainWindow;

import java.awt.EventQueue;
import java.net.Socket;
import java.util.HashMap;

import javax.swing.JOptionPane;

//import javax.sql.ConnectionPoolDataSource;

import common.ControlMessage;
import common.Logger;
import common.Message;
import common.ConnectionManager;
import common.MessageType;

public class Client extends Thread {
	
	private static Logger log = new Logger(true, false);
	
	//private static final int defaultPort = 31000;
	//private static final String defaultIp = "192.168.1.102";
	
	public String myLogin;
	
	private HashMap<Integer, ClientChatWindow> chats;
	
	private int port;
	private String ip;
	
	private int backupPort = 0;
	private String backupIp = null;
	
	private ClientMainWindow cmw;
	
	private boolean running;
	// timeout in seconds
	public static final int timeout = 30;
	
	private ConnectionManager connManager;
	private boolean logged;
	
	
	public static void main(String[] args) {
		int port;
		String ip;
		
		//ip = "89.68.11.229";
		//ip = "192.168.1.102";
		ip = "127.0.0.1";
		port = 31000; //defaultPort;
		
		//new Client(ip, port);
		
		connectServer(ip, port);
		
		return;

	}
	
	public static void connectServer(String ip, int port) {
		new Client(ip, port);
	}
	
	private void resetEnv(String ip, int port) {
		this.ip = ip;
		this.port = port;
		this.running = true;
		this.chats = new HashMap<Integer, ClientChatWindow>();

		this.logged = false;
	}
	
	public Client(String ip, int port) {
		
		resetEnv(ip, port);
		
		gui.ClientMainWindow.openWindow(this);
		
		this.start();
	}
	
	private synchronized boolean IsLogged() {
		return logged;
	}
	
	private synchronized void setLogged(boolean bool) {
		logged = bool;
	}
	
	public void run() {
		
		while (running) {
			
			//if (IsLogged()) 
				//log.log("Socket connection established");
			while(IsLogged()) {
				
				ControlMessage msg = connManager.receiveMessage();
				
				if (msg != null) {
					if (msg.getType() == MessageType.MESSAGE) {
						Message msg2 = (Message)msg;
						System.out.println("getchat " + msg2.getRoomID());
						// czy nie trzeba tu dac clonów?
						getChat(msg2.getRoomID()).appendMessage(msg2.getWho(), msg2.getStr(), msg2.getList());  
					}
					if (msg.getType() == MessageType.ROOM_INVITATION) {
						Message msg2 = (Message)msg;
						ClientChatWindow.openWindow(this, cmw, Integer.parseInt(msg2.getStr()), cmw.getClientName());
					}
					if (msg.getType() == MessageType.DISCONNECT) {
						log.log("Logged out");
						
						if (IsLogged())
							EventQueue.invokeLater(new Runnable() {
								public void run() {
									JOptionPane.showMessageDialog(null, "You have been logged out", "Chat", JOptionPane.ERROR_MESSAGE);
								}
							});
						
						logout();
						disconnect();
					}
					if (msg.getType() == MessageType.MEMBERS_UPDATE) {
						Message msg2 = (Message)msg;
						while(getChat(msg2.getRoomID()) == null) {
							System.out.println(getChat(msg2.getRoomID()));
							try {
								Thread.sleep(200);
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
						getChat(msg2.getRoomID()).updateMembers(msg2.getList());
					}
					if (msg.getType() == MessageType.BACKUP_SERVER) {
						Message msg2 = (Message) msg;
						backupIp = msg2.getStr();
						backupPort = msg2.getRoomID();
						System.out.println("Backup server: " + backupIp + ", " + backupPort);
					}
					
				} else {
					System.out.println("Oopsie, got null...");
					connManager.setEnabled(false);
					if (backupIp != null && !backupIp.equals("") && backupPort != 0) {
						System.out.println("Trying the backup server...");
						//ip = backupIp;
						//port = backupPort;
						
						logout();
						disconnect();
						resetEnv(backupIp, backupPort);
						
						//disconnect();
						connManager = null;
						
						if (login(myLogin) == true) {
							cmw.login(myLogin);
							System.out.println("OK!");
						} else
							System.out.println("Nie udalo sie zalogowac!");
							//logout();
					} else {
						System.out.println("Server down, no backup server available!");
						connManager.setEnabled(false);
						logout();
						connManager.setEnabled(true);
						
						EventQueue.invokeLater(new Runnable() {
							public void run() {
								JOptionPane.showMessageDialog(null, "Server down", "Chat", JOptionPane.ERROR_MESSAGE);
							}
						});
					}
				}
			}
			
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			System.out.println("Client finished execution");

		}
		
	}
	
	
	public boolean connect() {
		Socket socket;
		
		log.log("Trying " + ip + " and port " + port);
		if (ip != null && ip.length() > 0 && ip.charAt(0) == '/')
			ip = ip.substring(1);
		
		try {
			socket = new Socket(ip, port);
		} catch (Exception e) {
			log.log("Couldn't create connection with server on ip " + ip + " and port " + port);
			return false;
		}
		
		this.connManager = new ConnectionManager(socket);
		
		return true;
	}
	
	public boolean disconnect() {
		
		this.connManager.close();
		
		return true;
	}
	
	public boolean login(String name) {
		Message connect = new Message(MessageType.CONNECT, name);
		final Message connected;
		
		connect();
		
		if (connManager == null)
			return false;
		
		if (IsLogged()) {
			log.log("Logged in already");
			return false;
		}
		
		log.log("Loging to the server...");
		
		connManager.sendMessage(connect);
		connected = connManager.receiveMessage(); 
		
		if ((connected != null) && (connected.getType() == MessageType.CONNECT)) {
			log.log("Logged to server");
			setLogged(true);
			
			myLogin = name;
			
			return true;
		}
		else if (connected != null) {
			
			EventQueue.invokeLater(new Runnable() {
				public void run() {
					JOptionPane.showMessageDialog(null, "Could not login: " + connected.getStr(), "Chat", JOptionPane.ERROR_MESSAGE);
				}
			});
			
			return false;
			
		} else if (connected == null) {
			EventQueue.invokeLater(new Runnable() {
				public void run() {
					JOptionPane.showMessageDialog(null, "Server down", "Chat", JOptionPane.ERROR_MESSAGE);
				}
			});
		}
		
		return false;
	}
	
	public synchronized boolean logout() {
		Message disconnect;
		
		if (IsLogged() == false) {
			log.log("Logged out already");
			return false;
		}
		
		cmw.logout();
		
		for (Integer i : chats.keySet()) {
			//chats.get(i).showIt();
			chats.get(i).disable();
			leaveRoom(i);
		}
		
		setLogged(false);
		
		if (connManager.isEnabled()) {
			disconnect = new Message(MessageType.DISCONNECT);
			
			log.log("Loging out...");
			
			connManager.sendMessage(disconnect);
		}
		
		return true; //troche lipa
	}
	
	public synchronized void leaveRoom(int id) {
		
		if (IsLogged() && connManager.isEnabled())
			connManager.sendMessage(new Message(MessageType.ROOM_LEAVE, String.valueOf(id)));
		//System.out.println("TUUUUUUUUUUUUUUU");
	}
	
	
	public synchronized boolean sendChatMessage(String msg, String who, int roomID) {
		if (!IsLogged())
			return false;
		connManager.sendMessage(new Message(MessageType.MESSAGE, msg, null, who, roomID));
		return true;
	}
	
	public synchronized void sendCreateRoomMessage(String name) {
		log.log("A");
		connManager.sendMessage(new Message(MessageType.ROOM_CREATE, name));
		log.log("B");
	}
	
	public synchronized void sendInviteMessage(String msg, int roomID) {
		connManager.sendMessage(new Message(MessageType.ROOM_INVITE, msg, null, null, roomID));
	}
	
	public synchronized void addChat(int i, ClientChatWindow ccw) {
		chats.put(i, ccw);
	}
	
	public ClientChatWindow getChat(int i) {
		return chats.get(i);
	}
	
	public void removeChat(int i) {
		chats.remove(i);
	}
	
	public void set(ClientMainWindow cmw) {
		this.cmw = cmw;
	}
	
	public void close() {
		running = false;
		
		for (Integer i : chats.keySet()) {
			chats.get(i).close();
		}
	}
}
